package Cantella::DJabberd::Store::Result::User;

use base qw/DBIx::Class/;
use metaclass 'Reaction::Meta::Class';
use Moose;

use Set::Object ();
use MooseX::Types::Moose qw(ArrayRef Int);
use Reaction::Types::Core qw/NonEmptySimpleStr Password/;
use Reaction::Types::DateTime ();

use aliased 'Cantella::DJabberd::Store::Result::UserJid';
use aliased 'Cantella::DJabberd::Store::Result::UserRole';

has id => (is => 'ro', required => 1, isa => Int);
has username => (is => 'rw', required => 1, isa => NonEmptySimpleStr);
has password => (is => 'rw', required => 1, isa => Password);
has full_name => (is => 'rw', required => 1, isa => NonEmptySimpleStr);

has created_d => (is => 'ro', required => 1, isa =>  Reaction::Types::DateTime::DateTime);
has deleted_d => (is => 'rw', required => 0, isa =>  Reaction::Types::DateTime::DateTime);
has modified_d => (is => 'ro', required => 1, isa =>  Reaction::Types::DateTime::DateTime);

has jids      => (isa => ArrayRef, reader => 'get_jids' );

has roles => (
              isa => ArrayRef,
              reader => 'get_roles',
              writer => 'set_roles',
             );

use namespace::clean -except => [ 'meta' ];

{
  no warnings 'redefine';
  *get_jids  = sub { [ shift->jids->all  ] };
  *get_roles = sub { [ shift->roles->all ] };
}

__PACKAGE__->load_components(qw/EncodedColumn TimeStamp Core/);
__PACKAGE__->table('users');
__PACKAGE__->add_columns
  (
   id        => {
                 data_type => "INT",
                 size      => 10 ,
                 default_value => undef,
                 is_nullable   => 0,
                 is_auto_increment => 1,
                 extra => { unsigned => 1 },
                },
   username  => {
                 data_type => "VARCHAR",
                 size      => 255,
                 default_value => "",
                 is_nullable   => 0,
                },
   password  => {
                 data_type => "VARCHAR",
                 size      => 43 + 16,
                 default_value => "",
                 is_nullable   => 0,
                 encode_column => 1,
                 encode_class => 'Digest',
                 encode_check_method => 'check_password',
                 encode_args => {
                                 format      => 'base64',
                                 algorithm   => 'SHA-256',
                                 salt_length => 16,
                                },
                },
   full_name => {
                 data_type => "VARCHAR",
                 size      => 255,
                 default_value => "",
                 is_nullable   => 0,
                },

   created_d => {
                 set_on_create => 1,
                 data_type => "DATETIME",
                 is_nullable => 0,
                },
   modified_d => {
                  set_on_create => 1,
                  set_on_update => 1,
                  data_type => "DATETIME",
                  is_nullable => 0,
                 },
   deleted_d  => {
                  data_type => "DATETIME",
                  default_value => undef,
                  is_nullable => 1,
                 },
  );

__PACKAGE__->set_primary_key('id');
__PACKAGE__->add_unique_constraint(username => ['username']);

__PACKAGE__->has_many(jids => UserJid, { 'foreign.user_id' => 'self.id' });
__PACKAGE__->has_many(user_roles => UserRole, { 'foreign.user_id' => 'self.id' });
__PACKAGE__->many_to_many(roles => 'user_roles', 'role');

sub display_name { shift->username }

#try to build in cache support here ?
sub check_roles {
  my $self = shift;
  my $need = Set::Object->new( @_ );
  my $have = Set::Object->new( $self->roles->get_column('name')->all );
  return $have->superset($need);
}

sub check_any_role {
  my $self = shift;
  my $need = Set::Object->new( @_ );
  my $have = Set::Object->new( $self->roles->get_column('name')->all );
  return $have->intersection($need)->size > 0;
}

sub delete {
  my $self = shift;
  $self->deleted_d(\'NOW()');
  $self->update;
}

sub undelete {
  my $self = shift;
  $self->deleted_d(undef);
  $self->update;
}

*check_role = \ *check_roles;

__PACKAGE__->meta->make_immutable(inline_constructor => 0);

1;

__END__;

#    prefix => {
#                   data_type => "VARCHAR",
#                   size      => 255,
#                   default_value => "",
#                   is_nullable   => 0,
#                  },

#    suffix => {
#                   data_type => "VARCHAR",
#                   size      => 255,
#                   default_value => "",
#                   is_nullable   => 0,
#                  },

#    prefered_name => {
#                   data_type => "VARCHAR",
#                   size      => 255,
#                   default_value => "",
#                   is_nullable   => 0,
#                  },

#    first_name => {
#                   data_type => "VARCHAR",
#                   size      => 255,
#                   default_value => "",
#                   is_nullable   => 0,
#                  },

#    middle_name => {
#                  data_type => "VARCHAR",
#                  size      => 255,
#                  default_value => "",
#                  is_nullable   => 0,
#                 },

#    last_name => {
#                  data_type => "VARCHAR",
#                  size      => 255,
#                  default_value => "",
#                  is_nullable   => 0,
#                 },


#    first_name => {
#                   data_type => "VARCHAR",
#                   size      => 255,
#                   default_value => "",
#                   is_nullable   => 0,
#                  },
